#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <list>
#include <string.h>
#include <cstring>
#include <assert.h>
#include <time.h>
#include "mpi.h"

using namespace std;

int malloc2dfloat(float ***array, int n, int m) {

    /* allocate the n*m contiguous items */
    float *p = (float *)malloc(n*m*sizeof(float));
    if (!p) return -1;

    /* allocate the row pointers into the memory */
    (*array) = (float **)malloc(n*sizeof(float*));
    if (!(*array)) {
       free(p);
       return -1;
    }

    /* set up the pointers into the contiguous memory */
    for (int i=0; i<n; i++) 
       (*array)[i] = &(p[i*m]);

    return 0;
}

int free2dfloat(float ***array) {
    /* free the memory - the first element of the array is at the start */
    free(&((*array)[0][0]));

    /* free the pointers into the memory */
    free(*array);

  return 0;
}

int malloc2dUnsignedShort(unsigned short ***array, int n, int m) 
{
	unsigned short *p = (unsigned short *)malloc(n*m*sizeof(unsigned short));
	if (!p) 
		return -1;

	(*array) = (unsigned short **)malloc(n*sizeof(unsigned short*));
	if (!(*array)) 
	{
		free(p);
		return -1;
	}

	for (int i=0; i<n; i++) 
	(*array)[i] = &(p[i*m]);

	return 0;
}

int free2dUnsignedShort(unsigned short ***array) 
{
	free(&((*array)[0][0]));
	free(*array);
	return 0;
}


int main(int argc, char * argv[])
{
	int myId, numProcs, sendcount, recvcount, source;

	unsigned short** sendbuf;
	unsigned short** recvbuf;
	malloc2dUnsignedShort(&sendbuf, 4, 4);
	malloc2dUnsignedShort(&recvbuf, 4, 4);
/*
	float** sendbuf;
	sendbuf = new float*[4];
	for(int i = 0; i < 4; ++i)
   		sendbuf[i] = new float[4];*/
	unsigned short ii = 1;
	for(int i = 0; i < 4; ++i)
		for(int j = 0; j < 4; ++j)
		{
			sendbuf[i][j]=ii;
			ii++;
		}

	for(int i = 0; i < 4; ++i)
		for(int j = 0; j < 4; ++j)
		{
			std::cout<<", "<<sendbuf[i][j];
		}
	std::cout<<std::endl;
	
/*	float sendbuf[4][4] =  {
			  {1.0, 2.0, 3.0, 4.0},
			  {5.0, 6.0, 7.0, 8.0},
			  {9.0, 10.0, 11.0, 12.0},
			  {13.0, 14.0, 15.0, 16.0}  };*/
/*	unsigned short recvbuf[4][4] = {
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0} };*/
	int tag = 1;
	int* sendBufferEncodedValue;
	int* receiveBufferEncodedValue;
	MPI_Status stat;
	const int CoordinatesVectorDim = 2;
	unsigned long PopulationSize = 20;

	sendBufferEncodedValue = new int[PopulationSize];
	receiveBufferEncodedValue = new int[PopulationSize];
	sendBufferEncodedValue[0] = 11;
	receiveBufferEncodedValue[0] = 0;

	MPI_Init(&argc,&argv);           
    	MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
	MPI_Comm_rank(MPI_COMM_WORLD,&myId);
	std::cout<<"Uruchomiono proces: "<<myId<<std::endl;
	
	if(numProcs==4)
	//if((j%step == 0) && (j!=0))
	{
		int sendcount = 16;
		if (myId == 0)
		{ 	// odbierz listy od wszystkich procesow
			//zapakuj do jednej, wybierz najlepsza czesc 

			//rozeslij 
			std::cout<<"*********SEND  "<<sendcount<<std::endl;	
			for (int p=0; p<numProcs; p++) 
			{
				MPI_Send(&(sendbuf[0][0]), 5, MPI_UNSIGNED_SHORT, p, tag, MPI_COMM_WORLD);
				MPI_Send(sendBufferEncodedValue, sendcount, MPI_FLOAT, p, tag, MPI_COMM_WORLD);
			}
		}
		
		else
		{ // wyslij liste do procesu 0 i poczekaj na to co ci odesle
		}
		MPI_Recv(&(recvbuf[0][0]), 5, MPI_UNSIGNED_SHORT, 0, tag, MPI_COMM_WORLD, &stat); 
		MPI_Recv(receiveBufferEncodedValue, sendcount, MPI_FLOAT, 0, tag, MPI_COMM_WORLD, &stat);	
		//MPI_Barrier(MPI_COMM_WORLD);
		std::cout<<"Proces: "<<myId<<" bufor: "<<recvbuf[0][0]<<", "<<recvbuf[0][1]<<", "<<recvbuf[0][2]<<", "<<recvbuf[0][3]<<", "<<recvbuf[1][0]<<" bufor2: "<<receiveBufferEncodedValue[0]<<std::endl;
		//int MPI_Scatter*/
	}

	MPI_Finalize();
	free2dUnsignedShort(&sendbuf);
	return EXIT_SUCCESS;
}
